#region Using's

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

#endregion

namespace MyUtils
{
	[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Class,
		Inherited = false, AllowMultiple = true)]
	public sealed class WeakCachingAttribute : Attribute {}

	public static class Factory
	{
		internal static object FactorySync = new object();
		internal static Dictionary<object, object> ObjectsCollection = new Dictionary<object, object>();

		public static void ClearAllObjects()
		{
			lock (FactorySync)
			{
				ObjectsCollection.Clear();
			}
		}
	}

	//internal struct TypeInfo
	//{
	//    public bool? IsSingletone;
	//}

	public static class Factory<T> where T : class, new()
	{
		//public delegate void Args(T obj);

		//const string errCtor =
		//    "You must provide type that have constructor without arguments. It can have any visibility.";

		//public static Args SingletoneCreationAspect;
		//public static Args SingletoneRetrivalAspect;
		//private static Factory<T> theInstance;

		//private static TypeInfo typeInfo;

		//protected Factory()
		//{
		//}

		//public T this[object i_]
		//{
		//    get
		//    {
		//        var i = i_.ToString();
		//        if (typeInfo.IsSingletone == true)
		//        {
		//            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
		//                                                              "Retriving object of type '{0}' by name '{1}' - this type is declared as singletone, and can be accessed only by Factory<TypeName>.Singleton",
		//                                                              typeof (T).Name, i));
		//        }
		//        typeInfo.IsSingletone = false;

		//        var res = getObject(i);
		//        OnObjectRetrivalAspect(res);
		//        return res;
		//    }
		//}

		//static T _singletone = new T();
		[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
		public static T Singleton
		{
			get
			{
				lock (Factory.FactorySync)
				{
					object r;
					if (!Factory.ObjectsCollection.TryGetValue(typeof(T), out r))
					{
						Factory.ObjectsCollection[typeof(T)] = r = new T();
					}
					return (T)r;
				}
			}
		}

		//public static Factory<T> Get {
		//    get {
		//        if (theInstance == null) theInstance = new Factory<T>();
		//        return theInstance;
		//    }
		//}

		//public static T Singleton
		//{
		//    get
		//    {
		//        if (typeInfo.IsSingletone == false)
		//        {
		//            throw new InvalidOperationException("Try recive singletone for named object");
		//        }
		//        typeInfo.IsSingletone = true;

		//        T res = getObject(null);
		//        OnObjectRetrivalAspect(res);
		//        return res;
		//    }
		//}

		//private static T addToCollection(string name)
		//{
		//    var ctrs =
		//        typeof (T).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

		//    ConstructorInfo ctor = null;
		//    for (int i = 0; i < ctrs.Length; i++)
		//    {
		//        if (ctrs[i].GetParameters().Length == 0)
		//        {
		//            ctor = ctrs[0];
		//            break;
		//        }
		//    }
		//    if (ctor == null) throw new ArgumentException(errCtor);

		//    var res = (T) ctrs[0].Invoke(new object[0]);
		//    string internalName = getInternalObjectNameFor(name);
		//    if (isWeakType())
		//    {
		//        Factory.ObjectsCollection[internalName] = new WeakReference(res);
		//    }
		//    else
		//    {
		//        Factory.ObjectsCollection[internalName] = res;
		//    }
		//    Debug.WriteLine("MySpring: Object Created: " + internalName);
		//    OnObjectCreationAspect(res);
		//    return res;
		//}

		//private static string getInternalObjectNameFor(string name)
		//{
		//    string typeName = typeof (T).FullName;
		//    if (string.IsNullOrEmpty(name)) return typeName;
		//    return typeName + " " + name;
		//}

		//private static bool isWeakType()
		//{
		//    object[] atrs =// typeof (T).GetCustomAttributes(typeof (WeakCachingAttribute), true);
		//    return (atrs.Length > 0);
		//}

		//private static T getObject(string name)
		//{
		//    var internalName = getInternalObjectNameFor(name);
		//    var typeExists = Factory.ObjectsCollection.ContainsKey(internalName);

		//    if (!typeExists)
		//    {
		//        return addToCollection(name);
		//    }

		//    if (isWeakType())
		//    {
		//        var weak = (((WeakReference) Factory.ObjectsCollection[internalName]).Target);
		//        if (weak == null)
		//            return addToCollection(name);
		//        return (T) weak;
		//    }
		//    return (T) Factory.ObjectsCollection[internalName];
		//}

		//private static void OnObjectRetrivalAspect(T obj)
		//{
		//    if (SingletoneRetrivalAspect != null) SingletoneRetrivalAspect(obj);

		//    if (Factory<object>.SingletoneRetrivalAspect != null)
		//        if (typeof (T) != typeof (object))
		//            Factory<object>.SingletoneRetrivalAspect(obj);
		//}

		//private static void OnObjectCreationAspect(T obj)
		//{
		//    if (SingletoneCreationAspect != null) SingletoneCreationAspect(obj);

		//    if (Factory<object>.SingletoneCreationAspect != null)
		//        if (typeof (T) != typeof (object))
		//            Factory<object>.SingletoneCreationAspect(obj);
		//}
	}
}